package com.punai.config.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.punai.common.core.domain.entity.SysPnDictionary;
import com.punai.common.core.page.PageDomain;
import com.punai.common.core.page.TableDataInfo;
import com.punai.common.core.page.TableSupport;
import com.punai.common.utils.PnDictUtil;
import com.punai.config.constants.PnConfigConstants;
import com.punai.config.service.ConfigTemplateService;
import com.punai.config.sqlitedao.*;
import com.punai.config.sqlitedomain.*;
import com.punai.config.sqlitedomain.bo.StructureLinkItemBo;
import com.punai.config.sqlitedomain.vo.ConfigTemplateItemVo;
import com.punai.config.sqlitedomain.vo.ConfigUpdateStructLinkItemVo;
import io.netty.util.internal.StringUtil;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ConfigTemplateServiceImpl implements ConfigTemplateService {

    @Autowired
    private TemplateRepository templateRepository;
    @Autowired
    private StructureRepository structureRepository;
    @Autowired
    private StructureLinkTemplateRepository structureLinkTemplateRepository;
    @Autowired
    private StructureLinkItemRepository structureLinkItemRepository;
    @Autowired
    private TemplateLinkItemRepository templateLinkItemRepository;
    @Autowired
    private IndicatorItemRepository indicatorItemRepository;

    @Override
    public Page initMainTable(Map<String, Object> toMap, Pageable pagination) {
        return null;
    }

    @Override
    public Template findOne(String id) {
        return templateRepository.findOne(id);
    }

    @Override
    public String getNewCode() {
        String prefix = PnConfigConstants.TEMPLATE_TYPE.getPrefixByType("0");
        Template dbTemplate = templateRepository.findMaxTemplateCode();
        if (null == dbTemplate || StringUtils.isBlank(dbTemplate.getCode())) {
            return prefix + String.format("%03d", 1);
        } else {
            Integer nCode = Integer.parseInt(StringUtils.removeStart(dbTemplate.getCode(), prefix)) + 1;
            return prefix + String.format("%0" + (dbTemplate.getCode().length() - prefix.length()) + "d", nCode);
        }
    }

    @Override
    public String getNewStructureCode() {
        String startStr = "IS";
        String code = "";
        Integer maxPx=structureRepository.findMaxSorting();
        if (maxPx == null) {
            //第一次添加指标表
            code = startStr + "0001";
        } else {
            int i = maxPx + 1;
            code = startStr + String.format("%0" + 4 + "d", i);
        }
        return code;
    }

    @Override
    public void copyTemplate(String oid, Template model) {
        Template save = templateRepository.save(model);
        String saveTemplateId = save.getId();
        List<Structure> structureList = structureRepository.findByTemplateId(oid);
        List<TemplateLinkItem> all = templateLinkItemRepository.findAll(oid);
        List<String> itemIds = all.stream().map(TemplateLinkItem::getElementId).collect(Collectors.toList());
        templateLinkItemRepository.save(saveTemplateId,itemIds);
        Integer maxSorting = structureRepository.findMaxSorting();
        for (Structure structure : structureList) {
            String id = structure.getId();
            maxSorting++;
            structure.setSorting(maxSorting);
            structure.setId(null);
            Structure structuresave = structureRepository.save(structure);
            structureLinkTemplateRepository.save(new StructureLinkTemplate(structuresave.getId(), saveTemplateId));

            List<StructureLinkItem> linkItems = structureLinkItemRepository.findByStrutsId(id);
            Integer newMaxSorting = structureLinkItemRepository.findMaxSorting();
            for (StructureLinkItem linkItem : linkItems) {
                newMaxSorting++;
                linkItem.setSorting(newMaxSorting);
                linkItem.setStrutsId(structuresave.getId());
                structureLinkItemRepository.save(linkItem);
            }
        }
    }

    @Override
    public void saveTemplate(Template model) {
        String copyId = model.getCopyId();
        if (StrUtil.isNotBlank(copyId)) {
            this.copyTemplate(copyId, model);
        } else {
            templateRepository.save(model);
        }
    }

    @Override
    public void removeTemplate(String oid) {
        templateRepository.delete(oid);
        List<Structure> strutsTab = this.findStrutsTab(oid);
        for (Structure structure : strutsTab) {
            this.removeStruts(oid,structure.getId());
        }
    }

    @Override
    public List<Structure> findStrutsTab(String templateId) {
        return structureRepository.findByTemplateId(templateId);
    }

    @Override
    public Page initDetailTable(Map<String, Object> toMap, Pageable pagination) throws ParseException {
        return null;
    }

    @Override
    public Structure findOneOfStructure(String oid) {
        return structureRepository.findOne(oid);
    }

    @Override
    public Structure saveStruts(Structure structure) {
        String id = structure.getId();
        structure = structureRepository.save(structure);
        if (StrUtil.isBlank(id)) {
            structureLinkTemplateRepository.save(new StructureLinkTemplate(structure.getId(),structure.getTemplateId()));
        }
        return structure;
    }

    @Override
    public void removeStruts(String templateId, String strutsId) {
        List<StructureLinkItem> linkItems = structureLinkItemRepository.findByStrutsId(strutsId);
        structureRepository.remove(strutsId);
        structureLinkItemRepository.deleteByStrutsIdAndItemIds(strutsId, null, "1008611");
        for (StructureLinkItem linkItem : linkItems) {
            //处理模板与项的关系
            deleteTemplateLinkItem(templateId, linkItem);
        }
    }

    private void deleteTemplateLinkItem(String templateId, StructureLinkItem deleteOne)  {
        List<Structure> structures = structureRepository.findByTemplateId(templateId);
        List<StructureLinkItem> links = structureLinkItemRepository.findByStrutsId(structures.stream().map(Structure::getId).collect(Collectors.toSet()));
        links = links.stream().filter(v -> v.getElementId().equals(deleteOne.getElementId())).collect(Collectors.toList());
        if(links.size()==0){
            templateLinkItemRepository.delete(templateId, deleteOne.getElementId());
        }
    }

    @Override
    public Page initOrderTable(String templateId) {
        return null;
    }

    @Override
    public void saveOrder(String strutsId, String templateId, String type) {

    }

    @Override
    public void itemsOrder(String strutsId, String oid, String type) throws ParseException {

    }

    @Override
    public List<StructureLinkItem> findItemByStrutsIdAndItemPid(String strutsId, String itemPid) throws ParseException {
        return null;
    }

    @Override
    public void saveItem(String strutsId, String templateId, String itemPid, String selItemIds) {
        List<StructureLinkItem> oldLinks = structureLinkItemRepository.findByStrutsIdAndItemPid(strutsId, itemPid);
        List<String> itemIds = Arrays.asList(selItemIds.split(","));
        //筛选出不需要保存的
        Set<String> notSaveItemIds = oldLinks.stream()
                .filter(v -> itemIds.contains(v.getElementId()))
                .map(v -> v.getElementId()).collect(Collectors.toSet());

        List<String> saveItemIds = itemIds.stream().filter(v -> !notSaveItemIds.contains(v)).collect(Collectors.toList());
        templateLinkItemRepository.save(templateId,itemIds);
        Integer maxSorting = structureLinkItemRepository.findMaxSorting();
        List<SysPnDictionary> dictionarys = PnDictUtil.getDictionarys("041").stream().filter(v -> v.getName().equals("总建筑面积")).collect(Collectors.toList());
        for (String selItemId : saveItemIds) {
            maxSorting++;
            StructureLinkItem structureLinkItem = new StructureLinkItem();
            structureLinkItem.setSorting(maxSorting);
            structureLinkItem.setElementId(selItemId);
            structureLinkItem.setStrutsId(strutsId);
            structureLinkItem.setElementPid(itemPid);
            structureLinkItem.setIsHz("0");//默认不汇总

            structureLinkItem.setCalculationCode(dictionarys.size()>0? dictionarys.get(0).getCode():"");//默认无计算方式
            structureLinkItemRepository.save(structureLinkItem);
        }
    }

    @Override
    public void removeItem(String id, String templateId, String strutsId) {
        StructureLinkItem deleteOne = structureLinkItemRepository.delete(id);
        deleteTemplateLinkItem(templateId, deleteOne);
    }

    @Override
    public StructureLinkItemBo findItemByStrutsIdAndItemId(String strutsId, String oid) throws ParseException {
        return null;
    }

    @Override
    public StructureLinkItemBo findOneOfStructureLinkItem(String oid) throws ParseException {
        return null;
    }

    @Override
    public void settingItem(ConfigUpdateStructLinkItemVo vo) {
        StructureLinkItem one = structureLinkItemRepository.findOne(vo.getId());
        one.setCalculationCode(vo.getCalculationCode());
        one.setIsHz(vo.getIsHz());
        structureLinkItemRepository.updateCalculationCodeAndIsHz(one);
    }

    @Override
    public List<Template> findTemplateByType(String type) {
        return null;
    }

    @Override
    public TableDataInfo selectTemplateList() {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        PageRequest of = PageRequest.of(pageNum, pageSize);
        Page<Template> pageForMap = templateRepository.findPageForMap(new HashMap<>(), of);
        long totalElements = pageForMap.getTotalElements();
        List<Template> content = pageForMap.getContent();
        TableDataInfo tableDataInfo = new TableDataInfo();
        tableDataInfo.setRows(content);
        tableDataInfo.setTotal(totalElements);
        return tableDataInfo;
    }

    @Override
    public List<Template> selectAllTemplate() {
        return templateRepository.findAll();
    }

    @Override
    public TableDataInfo selectNoUsedItem(ConfigTemplateItemVo vo) {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        String structId = vo.getStructId();
        String indicatorType = vo.getIndicatorType();
        //
        TableDataInfo tableDataInfo = indicatorItemRepository.selectNoUsedItem(structId, indicatorType, pageNum, pageSize);
        return tableDataInfo;
    }

    @Override
    public List<StructureLinkItemBo> selectUsedItemList(ConfigTemplateItemVo vo) {
        String structId = vo.getStructId();
        List<StructureLinkItem> oldLinks=structureLinkItemRepository.findByStrutsId(structId);
        Set<String> itemIds = oldLinks.stream().map(StructureLinkItem::getElementId).collect(Collectors.toSet());
        List<ConfigIndicatorItem> items = indicatorItemRepository.findByIdIn(new ArrayList<>(itemIds));

        Map<String, ConfigIndicatorItem> itemMaps = items.stream().collect(Collectors.toMap(ConfigIndicatorItem::getId, Function.identity(), (v1, v2) -> v2));

        ArrayListValuedHashMap<String, StructureLinkItem> valuedHashMap = new ArrayListValuedHashMap<>();
        for (StructureLinkItem oldLink : oldLinks) {
            if(StringUtil.isNullOrEmpty(oldLink.getElementPid())) {
                oldLink.setElementPid("P");
            }
            valuedHashMap.put(oldLink.getElementPid(), oldLink);
        }

        List<StructureLinkItem> roots = valuedHashMap.get("P");
        List<StructureLinkItemBo> result = new ArrayList<>();
        if (CollUtil.isNotEmpty(roots)) {
            roots.sort(Comparator.comparing(StructureLinkItem::getSorting));
            for (StructureLinkItem root : roots) {
                String elementId = root.getElementId();
                ConfigIndicatorItem configIndicatorItem = itemMaps.get(elementId);
                StructureLinkItemBo conversion = StructureLinkItemBo.conversion(root, configIndicatorItem);
                result.add(conversion);
                setUsedItemChildren(conversion,valuedHashMap,itemMaps);
            }
        }
        return result;
    }

    @Override
    public void updateSort(String ids) {
        List<String> idList = StrUtil.split(ids, ",");
        for (int i = 0; i < idList.size(); i++) {
            structureRepository.updateSort(idList.get(i),i + 1);
        }
    }

    @Override
    public void updateItemSort(String id, String targetId) {

        StructureLinkItem source = structureLinkItemRepository.findOne(id);
        StructureLinkItem target = structureLinkItemRepository.findOne(targetId);

        Integer sourceSorting = source.getSorting();
        Integer targetSorting = target.getSorting();

        structureLinkItemRepository.updateSort(id,targetSorting);
        structureLinkItemRepository.updateSort(targetId,sourceSorting);
    }

    private void setUsedItemChildren(StructureLinkItemBo root, ArrayListValuedHashMap<String, StructureLinkItem> valuedHashMap,Map<String, ConfigIndicatorItem> itemMaps) {
        String pelementId = root.getElementId();
        List<StructureLinkItemBo> children = root.getChildren();
        List<StructureLinkItem> structureLinkItems = valuedHashMap.get(pelementId);
        if (CollUtil.isNotEmpty(structureLinkItems)) {
            structureLinkItems.sort(Comparator.comparing(StructureLinkItem::getSorting));
            for (StructureLinkItem child : structureLinkItems) {
                String elementId = child.getElementId();
                ConfigIndicatorItem configIndicatorItem = itemMaps.get(elementId);
                StructureLinkItemBo conversion = StructureLinkItemBo.conversion(child, configIndicatorItem);
                children.add(conversion);
                setUsedItemChildren(conversion,valuedHashMap,itemMaps);
            }
        }
    }
}
